using System;
using System.Workflow.Activities;
using System.Workflow.ComponentModel;
using Microsoft.Crm.Sdk;
using Microsoft.Crm.SdkTypeProxy;
using Microsoft.Crm.Workflow;
using Microsoft.Crm.Sdk.Query;
using System.Xml;
using System.Text.RegularExpressions;
using System.Web.Services.Protocols;

namespace CRM4ContractUtilities
{
    [CrmWorkflowActivity("Create Copy Contract", "Contract Utilities")]
    public class CreateCopyContract : System.Workflow.Activities.SequenceActivity
    {
        /// <summary>
        /// Contract
        /// </summary>
        public static DependencyProperty ContractIdProperty = DependencyProperty.Register("ContractId", typeof(Lookup), typeof(CreateCopyContract));
        [CrmInput("ContractId")]
        [CrmReferenceTarget("contract")]
        public Lookup ContractId
        {
            get { return (Lookup)base.GetValue(ContractIdProperty); }
            set { base.SetValue(ContractIdProperty, value); }
        }

        /// <summary>
        /// Start date of new contract 
        /// if not specified then it will defaulted from current date
        /// </summary>
        public static DependencyProperty startDateProperty = DependencyProperty.Register("startDate", typeof(CrmDateTime), typeof(CreateCopyContract));
        [CrmInput("startDate")]
        public CrmDateTime startDate
        {
            get { return (CrmDateTime)GetValue(startDateProperty); }
            set { SetValue(startDateProperty, value); }
        }

        /// <summary>
        /// end date of new contract 
        /// if not specified then it will defaulted from current date + 1 year
        /// </summary>
        public static DependencyProperty endDateProperty = DependencyProperty.Register("endDate", typeof(CrmDateTime), typeof(CreateCopyContract));
        [CrmInput("endDate")]
        public CrmDateTime endDate
        {
            get { return (CrmDateTime)GetValue(endDateProperty); }
            set { SetValue(endDateProperty, value); }
        }

        /// <summary>
        /// Contract
        /// </summary>
        public static DependencyProperty newContractIdProperty = DependencyProperty.Register("newContractId", typeof(Lookup), typeof(CreateCopyContract));
        [CrmOutput("newContractId")]
        [CrmReferenceTarget("contract")]
        public Lookup newContractId
        {
            get { return (Lookup)base.GetValue(newContractIdProperty); }
            set { base.SetValue(newContractIdProperty, value); }
        }

        protected override System.Workflow.ComponentModel.ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
        {

            IContextService contextService = (IContextService)executionContext.GetService(typeof(IContextService));
            IWorkflowContext context = contextService.Context;
            // Obtain IcrmService so we can call into CRM SDK to retrieve 
            // accounts                
            ICrmService crmService = context.CreateCrmService();

            //get text based on 
            CreateContracts(crmService, ContractId.Value.ToString()); 


            return ActivityExecutionStatus.Closed;


        }

        private void CreateContracts(ICrmService crmService, string sourceContractId)
        {
            try
            {
                DynamicEntity dynamicContract = RetrieveDynamicEntityForContract(crmService, sourceContractId);
                DateTime newStartDate = DateTime.Now;
                DateTime newEndDate = DateTime.Now.AddYears(1).AddSeconds(-1);

                if (dynamicContract != null)
                {
                    //invoice is created now update the existing orderline with the Invoice Number			
                    DynamicEntity newDynamicContract = new DynamicEntity();
                    newDynamicContract.Name = EntityName.contract.ToString();

                    //newDynamicContract.Properties = dynamicContract.Properties;
                    newDynamicContract.Properties = new PropertyCollection();
                    foreach (Property per in dynamicContract.Properties)
                    {
                        if (IsValidContractField(per.Name))
                        {
                            newDynamicContract.Properties.Add(per);
                        }
                    }

                    if (startDate != null && startDate.Value != null)
                    {
                        newStartDate = startDate.UniversalTime;
                    }

                    if (endDate != null && endDate.Value != null)
                    {
                        newEndDate = endDate.UniversalTime;
                    }
                    

                    newDynamicContract.Properties.Add(new CrmDateTimeProperty("activeon", CrmTypes.CreateCrmDateTimeFromUser(newStartDate)));
                    newDynamicContract.Properties.Add(new CrmDateTimeProperty("billingstarton", CrmTypes.CreateCrmDateTimeFromUser(newStartDate)));
                    newDynamicContract.Properties.Add(new CrmDateTimeProperty("expireson", CrmTypes.CreateCrmDateTimeFromUser(newEndDate)));
                    newDynamicContract.Properties.Add(new CrmDateTimeProperty("billingendon", CrmTypes.CreateCrmDateTimeFromUser(newEndDate)));



                    TargetCreateDynamic targetCreate = new TargetCreateDynamic();
                    targetCreate.Entity = newDynamicContract;

                    // Create the request object.
                    CreateRequest create = new CreateRequest();
                    create.Target = targetCreate;


                    CreateResponse created = (CreateResponse)crmService.Execute(create);

                    this.newContractId = new Lookup("contract", created.id);

                    //contract created now create the contract lines
                    CreateContractLines(crmService, sourceContractId, newContractId.Value.ToString(), newStartDate, newEndDate);      
                }
            }
            catch (SoapException ex)
            {
                throw (ex); 
            }
            catch (Exception ex)
            {
                throw (ex);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="fielName"></param>
        /// <returns></returns>
        private Boolean IsValidContractField(string fielName)
        {
            Boolean IsValid = true;
  
            
            if (fielName.Equals("contractid") || fielName.Equals("contractnumber") ||
                fielName.Equals("billingendon") || fielName.Equals("billingstarton") ||
                fielName.Equals("activeon") || fielName.Equals("expireson") ||
                fielName.Equals("statecode") || fielName.Equals("statuscode") 
                )
            {
                IsValid = false;
            }
            return IsValid;
        
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="fielName"></param>
        /// <returns></returns>
        private Boolean IsValidContractLineField(string fielName)
        {
            Boolean IsValid = true;
            
            if (fielName.Equals("contractid") || fielName.Equals("contractdetailid") ||                
                fielName.Equals("activeon") || fielName.Equals("expireson") ||
                fielName.Equals("statecode") || fielName.Equals("statuscode"))
            {
                IsValid = false;
            }
            return IsValid;

        }


        /// <summary>
        /// Retrieves the Contract objects
        /// </summary>
        /// <param name="myService">The CRM Service</param>
        /// <param name="searchId">The Search Id String</param>
        /// <returns>Contract Object</returns>
        private DynamicEntity RetrieveDynamicEntityForContract(ICrmService myService, string contractid)
        {
            DynamicEntity myDynamicEntity = null;
            try
            {

                QueryExpression query = new QueryExpression();
                query.ColumnSet = new AllColumns();



                query.EntityName = EntityName.contract.ToString();
                FilterExpression filter = new FilterExpression();
                query.Criteria = filter;

                ConditionExpression hasAccountNoOf = new ConditionExpression();
                filter.Conditions.Add(hasAccountNoOf);

                hasAccountNoOf.AttributeName = "contractid";
                hasAccountNoOf.Operator = ConditionOperator.Equal;
                hasAccountNoOf.Values = new string[] { contractid };


                // Retrieve the contact.
                RetrieveMultipleRequest req = new RetrieveMultipleRequest();
                req.Query = query;
                req.ReturnDynamicEntities = true;

                RetrieveMultipleResponse res
                   = (RetrieveMultipleResponse)myService.Execute(req);

                if (res.BusinessEntityCollection.BusinessEntities.Count == 1)
                {

                    foreach (BusinessEntity be in res.BusinessEntityCollection.BusinessEntities)
                    {
                        myDynamicEntity = (DynamicEntity)be;
                        break;
                    }
                }


            }
            catch (Exception ex)
            {
                //throw (ex);
            }
            return myDynamicEntity;

        }

        private void CreateContractLines(ICrmService crmService, string sourceContractId, string newContractId, DateTime newStartDate, DateTime newEndDate)
        {

            BusinessEntityCollection sourceContractlines = RetrieveContractLinesFromContract(crmService, sourceContractId);
            if (sourceContractlines != null && sourceContractlines.BusinessEntities.Count > 0)
            {
                foreach (BusinessEntity newlineEntity in sourceContractlines.BusinessEntities)
                {
                    DynamicEntity dynamicLineEntity = (DynamicEntity)newlineEntity;

                    //invoice is created now update the existing orderline with the Invoice Number			
                    DynamicEntity newDynamicContractLine = new DynamicEntity();
                    newDynamicContractLine.Name = EntityName.contractdetail.ToString();

                    //newDynamicContract.Properties = dynamicContract.Properties;
                    newDynamicContractLine.Properties = new PropertyCollection();
                    foreach (Property per in dynamicLineEntity.Properties)
                    {
                        if (IsValidContractLineField(per.Name))
                        {
                            newDynamicContractLine.Properties.Add(per);
                        }
                    }

                    
                    newDynamicContractLine.Properties.Add(new LookupProperty("contractid", CrmTypes.CreateLookup(EntityName.contract.ToString(),new Guid(newContractId))));
                    newDynamicContractLine.Properties.Add(new CrmDateTimeProperty("activeon", CrmTypes.CreateCrmDateTimeFromUser(newStartDate)));
                    newDynamicContractLine.Properties.Add(new CrmDateTimeProperty("expireson", CrmTypes.CreateCrmDateTimeFromUser(newEndDate)));
                    



                    TargetCreateDynamic targetCreate = new TargetCreateDynamic();
                    targetCreate.Entity = newDynamicContractLine;

                    // Create the request object.
                    CreateRequest create = new CreateRequest();
                    create.Target = targetCreate;


                    CreateResponse created = (CreateResponse)crmService.Execute(create);


                }
            }
        }

        /// <summary>
        /// Retrieves the Account objects
        /// </summary>
        /// <param name="myService">The CRM Service</param>
        /// <param name="searchId">The Search Id String</param>
        /// <returns>Account Identifier</returns>
        private BusinessEntityCollection RetrieveContractLinesFromContract(ICrmService myService, string contractId)
        {

            try
            {



                QueryExpression query = new QueryExpression();
                query.ColumnSet = new AllColumns();

                query.EntityName = EntityName.contractdetail.ToString();
                FilterExpression filter = new FilterExpression();
                query.Criteria = filter;

                ConditionExpression hasContractId = new ConditionExpression();
                hasContractId.AttributeName = "contractid";
                hasContractId.Operator = ConditionOperator.Equal;
                hasContractId.Values = new string[] { contractId };

                filter.Conditions.Add(hasContractId);

                // Retrieve the contact.
                RetrieveMultipleRequest req = new RetrieveMultipleRequest();
                req.Query = query;
                req.ReturnDynamicEntities = true;

                RetrieveMultipleResponse res
                   = (RetrieveMultipleResponse)myService.Execute(req);

                return res.BusinessEntityCollection;

            }
            catch (Exception ex)
            {
                return null;
            }


        }

    }
}

